import { parse } from './util.js';

const baseUrl = process.resourceUrl;

function sleep(ms) {
    return new Promise(resolve => {
        const timer = setTimeout(() => {
            clearTimeout(timer)
            resolve()
        }, ms)
    })
}

function deepAssign(target, source, path, deepth = 1) {
    function f(target, source, path, nowDeepth) {

        nowDeepth--;
        Object.keys(source).forEach(key => {
            if (nowDeepth === 0) {
                if (target[key] === undefined || target[key] === null) {
                    target[key] = source[key]
                }
            } else {
                if (target[key] === undefined || target[key] === null) {
                    target[key] = source[key]
                } else {
                    if (source[key] instanceof Object) {
                        f(target[key], source[key], `${path}.${key}`, nowDeepth)
                    } else {
                        target[key] = source[key]
                    }
                }
            }
        })
    }
    f(target, source, path, deepth)
}

function getPathObj(obj, pathArr) {
    let result = obj;
    if (!pathArr instanceof Array) {
        throw new Error('pathArr必须为数组');
    }
    if (pathArr.length === 1 && pathArr[0] === '') {
        return result;
    }
    if (pathArr.length === 2 && pathArr[0] === '' && pathArr[1] === '') {
        return result;
    }
    pathArr.forEach(item => {
        if (item.length === 0) {
            throw new Error(`请检查root:${pathArr.toString().replace(',', '/')}`)
        }
        if (!result[item]) {
            result[item] = {};
        }
        result = result[item];
    })
    return result;
}

export class Resource {
    constructor() {
        this.Content = {
            Character: {},
            Map: {
                Map: {
                    Map0: {},
                },
                Tile: {},
                Back: {},
                Obj: {},
                ['MapHelper.img']: {},
            },
            Sound: {
                [`Bgm00.img`]: {},
            },
            Effect: {
                ['BasicEff.img']: {},
            },
            OutSide: {},
        }
        this.cacheMark = {};

        this.mapCache = {
            Obj: [],
            Tile: [],
            Back: [],
            MapHelper: [],
            Sound: [],
        }
        this.effectCache = {
            BasicEff: [],
        }
        this.characterCache = {
            Body: [],
            Head: [],
            Weapon: [],
            Pants: [],
            Hair: [],
            Face: [],
            Coat: [],
            Afterimage: [],
        }
    }
    async load(root, url) {
        if (this.cacheMark[url]) {
            return
        }
        let result = this.Content;
        let path = root.split('/');
        result = getPathObj(result, path);
        const json = await (await fetch(baseUrl + url, {
            mode: 'cors',
            method: 'get'
        })).json();
        const { file, filename } = parse(json.dir);
        result[filename] = file;
        this.cacheMark[url] = true;
    }
    async loadMap(map_sort, map_id) {
        if (this.Content.Map.Map[map_sort][map_id]) {
            await sleep(800)
            return;
        }
        const req = await fetch('http://localhost:20048/map', {
            method: 'post',
            mode: 'cors',
            body: JSON.stringify({
                map_sort,
                map_id,
                cache: this.mapCache,
            }),
            headers: {
                "Content-Type": "application/json;charset=UTF-8"
            }
        })
        const json = await req.json()
        const { Map, mapCache } = json
        const { map, Obj, Back, Tile, MapHelper, Sound } = Map
        this.Content.Map.Map[map_sort][map_id] = map
        Object.keys(this.mapCache).forEach(key => {
            this.mapCache[key].push(...mapCache[key])
        })
        deepAssign(this.Content.Map.Obj, Obj, 'Obj', 4)
        deepAssign(this.Content.Map.Back, Back, 'Back', 3)
        deepAssign(this.Content.Map.Tile, Tile, 'Tile', 3)
        deepAssign(this.Content.Map['MapHelper.img'], MapHelper, 'MapHelper', 2)
        deepAssign(this.Content.Sound, Sound, 'Sound', 2)

    }
    async loadEffect() {
        const req = await fetch('http://localhost:20048/effect', {
            method: 'post',
            mode: 'cors',
            body: JSON.stringify({
                cache: this.effectCache,
            }),
            headers: {
                "Content-Type": "application/json;charset=UTF-8",
            }
        })
        const json = await req.json()
        const { Effect, effectCache } = json
        const { BasicEff } = Effect
        Object.keys(this.effectCache).forEach(key => {
            this.effectCache[key].push(...effectCache[key])
        })
        deepAssign(this.Content.Effect['BasicEff.img'], BasicEff, 'BasicEff', 1)
    }
    async loadPlayer(player) {
        const req = await fetch('http://localhost:20048/character', {
            method: 'post',
            mode: 'cors',
            body: JSON.stringify({
                cache: this.characterCache,
                player,
            }),
            headers: {
                "Content-Type": "application/json;charset=UTF-8"
            }
        })
        const json = await req.json()
        const { Character, characterCache } = json
        Object.keys(this.characterCache).forEach(key => {
            this.characterCache[key].push(...characterCache[key])
        })
        deepAssign(this.Content.Character, Character, 'Character', 2)
        console.log(this.Content.Character)
    }
    async loadOutSide(root, url) {
        if (this.cacheMark[url]) {
            return
        }
        let result = this.Content.OutSide;
        if (root.length !== 0) {
            let path = root.split('/');
            result = getPathObj(result, path);
        }
        const json = await (await fetch(baseUrl + url, {
            mode: 'cors',
            method: 'get'
        })).json();

        const filename = json.$.name;
        result[filename] = json;
        this.cacheMark[url] = true;
    }
}